package controllers

import (
	"github.com/astaxie/beego"
	"choujiang/models"
	"strconv"
	"time"
	"log"
	"math/rand"
	"net/http"
	"github.com/gorilla/websocket"
)

type DeviceController struct {
	beego.Controller
}

func (c *DeviceController) Prepare() {
	typeid := c.GetSession("type")
	deviceid := c.GetSession("deviceid")
	log.Println(deviceid)
	if typeid == nil || deviceid == nil || typeid.(int) == 0 || deviceid.(int) == 0 {
		c.Redirect("/login/device", 302)
	}
}

func (c *DeviceController) GetQrcodePage() {
	c.Data["Id"] = c.GetSession("deviceid").(int)
	models.DeleteCache("deviceuser" + strconv.Itoa(c.GetSession("deviceid").(int)))
	token := RandString(8)
	c.Data["token"] = token
	if err := models.PutIntoCache("devicetoken"+strconv.Itoa(c.GetSession("deviceid").(int)), token, time.Hour*5); err != nil {
		Json_Message(&c.Controller, 1, "put cache wrong:"+err.Error())
	}
	device := models.Devices{Id: c.GetSession("deviceid").(int)}
	if err := models.DeviceGetInfo(&device); err != nil || device.DeviceType == 0 {
		Message(&c.Controller, `/`, "系统错误！"+err.Error(), "", false)
	}
	c.Data["DeviceType"] = device.DeviceType
	c.TplName = "erweima.html"
}

func (c *DeviceController) RefreshToken() {
	token := RandString(8)
	if err := models.PutIntoCache("devicetoken"+strconv.Itoa(c.GetSession("deviceid").(int)), token, time.Hour*5); err != nil {
		Json_Message(&c.Controller, 1, "put cache wrong:"+err.Error())
	}
	Json_Message(&c.Controller, 0, token)
}

func (c *DeviceController) UpdateTime() {
	models.UpdateDeviceTime(c.GetSession("deviceid").(int))
	Json_Message(&c.Controller, 0, "update success")
}

func (c *DeviceController) GetPrisePage() {
	deviceuser := "deviceuser" + strconv.Itoa(c.GetSession("deviceid").(int))
	uid, _ := models.GetCacheInt(deviceuser)
	user := models.Users{Id: uid}
	if uid == 0 {
		models.DeleteCache(deviceuser)
		Message(&c.Controller, `/device/qrcode`, "扫码已经过期，即将跳转到二维码抽奖页面！", "", false)
	}
	if err := models.UsersGetInfo(&user); err != nil {
		models.DeleteCache(deviceuser)
		Message(&c.Controller, `/device/qrcode`, "用户信息获取错误，即将跳转到二维码抽奖页面！", "", false)
	}
	if exist, _ := models.GetCacheBool("choujiangId" + strconv.Itoa(uid)); exist {
		models.DeleteCache(deviceuser)
		Message(&c.Controller, `/device/qrcode`, "您的抽奖机会已经用完了，请下一个时段尝试，即将跳转到二维码抽奖页面！", "", false)
	}
	device := models.Devices{Id: c.GetSession("deviceid").(int)}
	if err := models.DeviceGetInfo(&device); err != nil || device.DeviceType != 1 {
		models.DeleteCache(deviceuser)
		Message(&c.Controller, `/device/qrcode`, "系统错误，设备类型已经更改，请重新扫码抽奖！", "", false)
	}
	pointModule := models.PointModule{Id: device.PointModule}
	if err := models.PointModuleGetInfo(&pointModule); err != nil {
		models.DeleteCache(deviceuser)
		Message(&c.Controller, `/device/qrcode`, "系统错误，获取积分模板错误，请重新扫码抽奖！", "", false)
	}

	c.Data["point"] = &pointModule
	c.Data["devicetype"] = device.DeviceType
	c.Data["deviceId"] = device.Id
	c.Data["user"] = &user
	rank, ranktype, point := GetResult(c, &user, &device, &pointModule)
	c.Data["rank"] = rank
	c.Data["ranktype"] = ranktype
	c.Data["pointValue"] = point
	c.TplName = "choujiang.html"
}

func GetResult(c *DeviceController, user *models.Users, device *models.Devices, pointModule *models.PointModule) (int, int, float32) {
	//deviceuser := "deviceuser" + strconv.Itoa(c.GetSession("deviceid").(int))
	//uid, _ := models.GetCacheInt(deviceuser)
	//if uid == 0 {
	//	models.DeleteCache(deviceuser)
	//	Json_Message(&c.Controller, 1, "扫码已经过期!")
	//}

	rand.Seed(time.Now().UnixNano())
	currentNum := rand.Intn(100000)
	rank := getRank(currentNum, pointModule)
	//get today Counts
	countTotal, count1, count2, count3 := getTodayCounts(strconv.Itoa(device.Id))

	//check exceed
	if rank == 1 {
		if count1 >= pointModule.MaxCount1 {
			for {
				rand.Seed(time.Now().UnixNano())
				currentNum := rand.Intn(100000)
				rank = getRank(currentNum, pointModule)
				if rank != 1 {
					break
				}
			}
		}
	} else {
		count1++
	}
	if rank == 2 {
		if count2 >= pointModule.MaxCount2 {
			for {
				rand.Seed(time.Now().UnixNano())
				currentNum := rand.Intn(100000)
				rank = getRank(currentNum, pointModule)
				if rank != 2 {
					break
				}
			}
		}
	} else {
		count2++
	}
	if rank == 3 {
		if count3 >= pointModule.MaxCount3 {
			for {
				rand.Seed(time.Now().UnixNano())
				currentNum := rand.Intn(100000)
				rank = getRank(currentNum, pointModule)
				if rank != 3 {
					break
				}
			}
		}
	} else {
		count3++
	}
	repeatTimes := 10
	//check min
	if rank != 1 && rank != 2 && rank != 3 {
		originrank := rank
		if countTotal >= pointModule.MinCount1Hold && count1 < pointModule.MinCount1 {
			i := 0
			for {
				rand.Seed(time.Now().UnixNano())
				currentNum := rand.Intn(100000)
				rank = getRank(currentNum, pointModule)
				if rank != 1 {
					rank = originrank
				}
				if i == repeatTimes || rank == 1 {
					if rank == 1 {
						count3++
					}
					break
				}
				i++
			}
		}
	}

	if rank != 1 && rank != 2 && rank != 3 {
		originrank := rank
		if countTotal >= pointModule.MinCount2Hold && count2 < pointModule.MinCount2 {
			i := 0
			for {
				rand.Seed(time.Now().UnixNano())
				currentNum := rand.Intn(100000)
				rank = getRank(currentNum, pointModule)
				if rank != 2 {
					rank = originrank
				}
				if i == repeatTimes || rank == 2 {
					if rank == 2 {
						count2++
					}
					break
				}
				i++
			}
		}
	}

	if rank != 1 && rank != 2 && rank != 3 {
		originrank := rank
		if countTotal >= pointModule.MinCount3Hold && count3 < pointModule.MinCount3 {
			i := 0
			for {
				rand.Seed(time.Now().UnixNano())
				currentNum := rand.Intn(100000)
				rank = getRank(currentNum, pointModule)
				if rank != 3 {
					rank = originrank
				}
				if i == repeatTimes || rank == 3 {
					if rank == 3 {
						count3++
					}
					break
				}
				i++
			}
		}
	}
	models.PutIntoCache("priseResult"+strconv.Itoa(device.Id), rank, time.Minute)
	ranktype, point := getRankTypeAndPoint(rank, pointModule)
	return rank, ranktype, point
}

func (c *DeviceController) GetPriseResult() {
	deviceuser := "deviceuser" + strconv.Itoa(c.GetSession("deviceid").(int))

	uid, _ := models.GetCacheInt(deviceuser)
	if uid == 0 {
		models.DeleteCache(deviceuser)
		Json_Message(&c.Controller, 1, "扫码已经过期!")
	}
	user := models.Users{Id: uid}
	if err := models.UsersGetInfo(&user); err != nil {
		Json_Message(&c.Controller, 1, "获取用户信息失败！"+err.Error())
	}
	device := models.Devices{Id: c.GetSession("deviceid").(int)}
	if err := models.DeviceGetInfo(&device); err != nil {
		Json_Message(&c.Controller, 1, "获取设备信息失败！"+err.Error())
	}
	pointModule := models.PointModule{Id: device.PointModule}
	if err := models.PointModuleGetInfo(&pointModule); err != nil {
		Json_Message(&c.Controller, 1, "获取模板信息失败！"+err.Error())
	}
	rank, _ := models.GetCacheInt("priseResult" + strconv.Itoa(device.Id))
	if rank == 0 {
		models.DeleteCache(deviceuser)
		models.DeleteCache("priseResult" + strconv.Itoa(device.Id))
		Json_Message(&c.Controller, 1, "系统错误，请重新扫码抽奖!")
	}

	rankFrontPage, _ := c.GetInt("rankFrontPage")
	if rankFrontPage != rank {
		models.DeleteCache(deviceuser)
		models.DeleteCache("priseResult" + strconv.Itoa(device.Id))
		Json_Message(&c.Controller, 1, "系统错误，请重新扫码抽奖!")
	}

	countTotal, count1, count2, count3 := getTodayCounts(strconv.Itoa(device.Id))
	countTotal++
	switch rank {
	case 1:
		count1++
		addCounts(device.Id, rank)
		break
	case 2:
		count2++
		addCounts(device.Id, rank)
		break
	case 3:
		count3++
		addCounts(device.Id, rank)
		break
	default:
		break
	}
	models.DeleteCache("deviceuser" + strconv.Itoa(c.GetSession("deviceid").(int)))
	//updateTodayCounts(strconv.Itoa(device.Id), countTotal, count1, count2, count3)
	if ranktype, point := getRankTypeAndPoint(rank, &pointModule); ranktype == 0 {
		go SendPoint(int(point), device, user)
	} else {
		go SendMoney(point, device, user)
	}
	Json_Message(&c.Controller, 0, rank)
}

func getTodayCounts(deviceId string) (countTotal, count1, count2, count3 int) {
	if countTotal, _ = models.GetCacheInt("deviceCount_Total" + deviceId); countTotal == 0 {
		models.PutIntoCache("deviceCount_Total"+deviceId, 0, time.Hour*20)
	}
	if count1, _ = models.GetCacheInt("deviceCount1_count" + deviceId); count1 == 0 {
		models.PutIntoCache("deviceCount1_count"+deviceId, 0, time.Hour*20)
	}
	if count2, _ = models.GetCacheInt("deviceCount2_count" + deviceId); count2 == 0 {
		models.PutIntoCache("deviceCount2_count"+deviceId, 0, time.Hour*20)
	}
	if count3, _ = models.GetCacheInt("deviceCount3_count" + deviceId); count3 == 0 {
		models.PutIntoCache("deviceCount3_count"+deviceId, 0, time.Hour*20)
	}
	return
}

func updateTodayCounts(deviceId string, countTotal, count1, count2, count3 int) {
	models.PutIntoCache("deviceCount_Total"+deviceId, countTotal, time.Hour*20)
	models.PutIntoCache("deviceCount1_count"+deviceId, count1, time.Hour*20)
	models.PutIntoCache("deviceCount2_count"+deviceId, count2, time.Hour*20)
	models.PutIntoCache("deviceCount3_count"+deviceId, count3, time.Hour*20)
}

func addCounts(deviceId int, prise int) error {
	return models.IncreaseCount("deviceCount" + strconv.Itoa(prise) + "_count" + strconv.Itoa(deviceId))
}

func getRank(currentNum int, point *models.PointModule) int {
	num := 0
	if (currentNum - num) < int(point.Probability1*100000) {
		return 1
	}
	if (currentNum - num) < int(point.Probability2*100000) {
		return 2
	}
	num += int(point.Probability2 * 100000)
	if (currentNum - num) < int(point.Probability3*100000) {
		return 3
	}
	num += int(point.Probability3 * 100000)
	if (currentNum - num) < int(point.Probability4*100000) {
		return 4
	}
	num += int(point.Probability4 * 100000)
	if (currentNum - num) < int(point.Probability5*100000) {
		return 5
	}
	num += int(point.Probability5 * 100000)
	if (currentNum - num) < int(point.Probability6*100000) {
		return 6
	}
	num += int(point.Probability6 * 100000)
	if (currentNum - num) < int(point.Probability7*100000) {
		return 7
	}
	num += int(point.Probability7 * 100000)
	if (currentNum - num) < int(point.Probability8*100000) {
		return 8
	}
	return 9
}

func getRankTypeAndPoint(rank int, point *models.PointModule) (int, float32) {
	if rank == 1 {
		return point.Point1Type, point.Point1
	}
	if rank == 2 {
		return point.Point2Type, point.Point2
	}
	if rank == 3 {
		return point.Point3Type, point.Point3
	}
	if rank == 4 {
		return point.Point4Type, point.Point4
	}
	if rank == 5 {
		return point.Point5Type, point.Point5
	}
	if rank == 6 {
		return point.Point6Type, point.Point6
	}
	if rank == 7 {
		return point.Point7Type, point.Point7
	}
	if rank == 8 {
		return point.Point8Type, point.Point8
	}
	if rank == 9 {
		return point.Point9Type, point.Point9
	}
	return 0, 0
}

func SendMoney(money float32, device models.Devices, user models.Users) {
	setCacheOfChoujiangInterver(user.Id)
	//time.Sleep(time.Second * 10)
	log.Println("send money:", money, user.WxOpenId)

	moneyModel := models.UserDevicePoint{UserId: user.Id, DeviceId: device.Id, Position: device.DevicePosition, Point: int(money), PointType: 1, GetTime: time.Now(), LoseEffectTime: time.Now().AddDate(0, 1, 0)}
	if err := models.UserDevicePointInsert(&moneyModel); err != nil {
		log.Fatalln("insert user total point wrong!", user.Id, money)
	}
	//todo
	sqlLogs := models.SQLLogs{UserId: user.Id, Body: "现金大奖！" + "奖金额度：" + strconv.FormatFloat(float64(money), 'g', 4, 32) + "元(现金)" + "中奖编号为：" + strconv.FormatInt(moneyModel.Id, 10) + "  用户Id为：" + strconv.Itoa(user.Id), LogTime: time.Now(), LogType: 1}
	models.SQLLogsInsert(&sqlLogs)
	go SendToWX_jifendaozhang(user.WxOpenId, "现金大奖！", strconv.FormatFloat(float64(money), 'g', 4, 32)+"元(现金)", time.Now().Format("2006-01-02 15:04:05"), "中奖编号为："+strconv.FormatInt(moneyModel.Id, 10)+"  用户Id为："+strconv.Itoa(user.Id), "", "", []string{user.WxOpenId}, "pWDc-LpD50jOglNEmlSzIbUuSlO7Cucn_jFeeYyBNAA")
}

func SendPoint(point int, device models.Devices, user models.Users) {
	setCacheOfChoujiangInterver(user.Id)
	//time.Sleep(time.Second * 1)
	log.Println("send point:", point, user.Id)

	if err := models.UserCurrentPointUpdate(&user, point); err != nil {
		log.Fatalln("update user current point wrong!", user.Id, point)
	}
	if err := models.UserTotalPointUpdate(&user, point); err != nil {
		log.Fatalln("update user total point wrong!", user.Id, point)
	}
	if err := models.UserDevicePointInsert(&models.UserDevicePoint{UserId: user.Id, DeviceId: device.Id, Position: device.DevicePosition, Point: point, PointType: 0, GetTime: time.Now(), LoseEffectTime: time.Now().AddDate(0, 1, 0)}); err != nil {
		log.Fatalln("insert user total point wrong!", user.Id, point)
	}
	sqlLogs := models.SQLLogs{UserId: user.Id, Body: "积分！" + "奖金额度：" + "(积分)," + "  用户Id为：" + strconv.Itoa(user.Id), LogTime: time.Now(), LogType: 2}
	models.SQLLogsInsert(&sqlLogs)
	//todo wxsend message
	go SendToWX_jifendaozhang(user.WxOpenId, "抽奖积分已发送到您账户", strconv.Itoa(point), time.Now().Format("2006-01-02 15:04:05"), "当前积分为："+strconv.FormatInt(user.UserCurrentPoint+int64(point), 10), "", "", []string{user.WxOpenId}, "pWDc-LpD50jOglNEmlSzIbUuSlO7Cucn_jFeeYyBNAA")
}

func setCacheOfChoujiangInterver(uid int) {
	models.PutIntoCache("choujiangId"+strconv.Itoa(uid), true, time.Hour*6)
}

func (c *DeviceController) JoinToSocket() {
	uname := c.GetString("Id")
	if len(uname) == 0 {
		c.Redirect("/", 302)
		return
	}

	// Upgrade from http request to WebSocket.
	ws, err := websocket.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil, 1024, 1024)
	if _, ok := err.(websocket.HandshakeError); ok {
		http.Error(c.Ctx.ResponseWriter, "Not a websocket handshake", 400)
		return
	} else if err != nil {
		beego.Error("Cannot setup WebSocket connection:", err)
		return
	}

	// Join chat room.
	Join(uname, ws)
	defer Leave(uname)

	// Message receive loop.
	for {
		_, p, err := ws.ReadMessage()
		if err != nil {
			return
		}
		publish <- newEvent(models.EVENT_MESSAGE, uname, string(p))
	}
}
